from lexer.token.EOF import EOF
from lexer.token.identifier import Identifier
from lexer.token.token import Token
from lexer.token.token_type import TokenType
from lexer.token.char import Char
from lexer.token.string import String

class Lexer:
    def __init__(self, fileName):
        self.pos = 0
        self.text = ""
        self.lineNumber = 0
        self.columnNumber = 0
        try:
            self.file = open(fileName)
        except IOError as e:
            print("打开文件失败：{0}".format(e))
        else:
            print("无法打开文件，错误未知")

    def getCurrentChar(self):
        if self.pos >= len(self.text):
            return None
        return self.text[self.pos]

    def advance(self, step = 1):
        self.pos += step
        if self.pos >= len(self.text):
            self.text = self.file.readline()
            self.lineNumber += 1
            self.columnNumber = 0

    def get_next_token(self):
        self.eatSpace()
        self.eatComment()
        self.eatInclude()

        current_char = self.getCurrentChar()
        if current_char == None:
            return EOF()
        elif current_char.isalpha():
            return self.parseIdentifierAndKeyword()
        elif current_char.isdigit():
            return self.parseNumber()
        elif current_char == "'":
            return self.parseChar()
        elif current_char == "\"":
            return self.parseString()
        elif current_char == "!":
            if self.nextChar() == "=":
                self.advance(2)
                return Token(TokenType.NOT_EQUAL)
            else:
                self.advance()
                return Token(TokenType.NOT)
        elif current_char == "+":
            if self.nextChar() == "+":
                self.advance(2)
                return Token(TokenType.INC)
            else:
                self.advance()
                return Token(TokenType.ADD)
        elif current_char == "-":
            if self.nextChar() == "-":
                self.advance(2)
                return Token(TokenType.DEC)
            else:
                self.advance()
                return Token(TokenType.SUB)
        elif current_char == "*":
            self.advance()
            return Token(TokenType.MULTIPLY)
        elif current_char == "/":
            self.advance()
            return Token(TokenType.DIVIDE)
        elif current_char == "%":
            self.advance()
            return Token(TokenType.MODULO)
        elif current_char == ">":
            if self.nextChar() == "=":
                self.advance(2)
                return Token(TokenType.GE)
            else:
                self.advance()
                return Token(TokenType.GT)
        elif current_char == "<":
            if self.nextChar() == "=":
                self.advance(2)
                return Token(TokenType.LE)
            else:
                self.advance()
                return Token(TokenType.LT)
        elif current_char == "=":
            if self.nextChar() == "=":
                self.advance(2)
                return Token(TokenType.EQUAL)
            else:
                self.advance()
                return Token(TokenType.ASSIGN)
        elif current_char == "&":
            if self.nextChar() == "&":
                self.advance(2)
                return Token(TokenType.AND)
            else:
                self.advance()
                return Token(TokenType.AMPERSAND)
        elif current_char == "|":
            if self.nextChar() == "|":
                self.advance(2)
                return Token(TokenType.OR)
            else:
                raise Exception("未知的token：{0}".format(current_char))
        elif current_char == "(":
            return Token(TokenType.LPAREN)
        elif current_char == ")":
            return Token(TokenType.RPAREN)
        elif current_char == "[":
            return Token(TokenType.LBRACK)
        elif current_char == "]":
            return Token(TokenType.RBRACK)
        elif current_char == "{":
            return Token(TokenType.LBRACE)
        elif current_char == "}":
            return Token(TokenType.RBRACE)
        elif current_char == ",":
            return Token(TokenType.COMMA)
        elif current_char == ":":
            return Token(TokenType.COLON)
        elif current_char == ";":
            return Token(TokenType.SEMI)
        else:
            raise Exception("未知的token：{0}".format(current_char))

    def eatSpace(self):
        while self.pos < len(self.text) and \
                self.text[self.pos] == " " or \
                self.text[self.pos] == "\n" or \
                self.text[self.pos] == "\t":
            self.advance()

    def eatComment(self):
        if self.pos + 1 < len(self.text) and self.text[self.pos: self.pos + 2] == "/*":
            while self.pos + 1 < len(self.text) and self.text[self.pos: self.pos + 2] != "*/":
                self.advance()
            if self.pos == len(self.text):
                raise Exception("注释没有结尾的*/")

    def eatInclude(self):
        if self.text[self.pos] == "#":
            while self.pos < len(self.text) and self.text[self.pos] != ">":
                self.pos += 1

    def parseIdentifierAndKeyword(self):
        result = ""
        while self.pos < len(self.text) and self.text[self.pos].isalpha():
            result += self.text[self.pos]
            self.advance()
        if Identifier.isKeyword(result):
            return Token(Identifier.keywordType(result))
        else:
            return Identifier(result)

    def parseNumber(self):
        result = ""
        while self.pos < len(self.text) and self.text[self.pos].isdigit():
            result += self.text[self.pos]
            self.advance()
        return int(result)

    def parseChar(self):
        self.advance()
        if self.pos + 1 >= len(self.text):
            raise Exception("错误的字符")
        char = None
        if self.text[self.pos] == "\\":
            char = Char(self.text[self.pos: self.pos + 2])
            self.advance(2)
        else:
            char = Char(self.text[self.pos])
            self.advance()
        # 校验字符右边的'
        if self.text[self.pos] != "'":
            raise Exception("错误的字符")
        self.advance()
        return char

    def parseString(self):
        result = ""
        self.advance()
        while self.pos < len(self.text) and self.text[self.pos].isalpha():
            result += self.text[self.pos]
            self.advance()
        if self.pos >= len(self.text) or self.text[self.pos] != "\"":
            raise Exception("错误的字符串")
        self.advance()
        return String(result)

    def nextChar(self):
        if self.pos + 1 < len(self.text):
            return self.text[self.pos + 1]
        else:
            return None
